package com.tuozixuan.onesql.ui;

import java.sql.SQLException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import org.apache.commons.lang3.StringUtils;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.tuozixuan.onesql.db.Column;
import com.tuozixuan.onesql.db.ConnectionInfo;
import com.tuozixuan.onesql.db.Database;
import com.tuozixuan.onesql.db.Table;
import com.tuozixuan.onesql.mysql.BaseDao;
import com.tuozixuan.onesql.service.TableContext;
import com.tuozixuan.onesql.service.TableServiceImpl;
import com.tuozixuan.onesql.ui.model.NavigationNode;

import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableColumn.CellDataFeatures;
import javafx.scene.control.TreeTableView;
import javafx.scene.control.cell.MapValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;

public class NavigationView {
    
    private List<ConnectionInfo> connectionInfoList;
    
    private TreeTableView<NavigationNode> treeTableView;
    
    private TabPane tabPane;
    
    private Map<String, String> tabHeaderColorMap = Maps.newHashMap();
    
    public NavigationView(BorderPane masterBorderPane, List<ConnectionInfo> connectionInfoList) {
        this.connectionInfoList = connectionInfoList;
        
        this.initTabPane();
        
        NavigationNode rootNavigationNode = new NavigationNode("NoteRoot", "root", 0);
        TreeItem<NavigationNode> treeItemRoot = new TreeItem<>(rootNavigationNode);
        treeItemRoot.setExpanded(true);
        for (ConnectionInfo connectionInfo : connectionInfoList) {
        	NavigationNode connectionNavigationNode = new NavigationNode(connectionInfo.getName(), "connection", 1);
            TreeItem<NavigationNode> treeItem = new TreeItem<>(connectionNavigationNode);
            treeItemRoot.getChildren().add(treeItem);
        }
        
        
        TreeTableColumn<NavigationNode, String> treeTableColumn = new TreeTableColumn<>("Column");
        treeTableColumn.setPrefWidth(300);
        treeTableColumn.setCellValueFactory((CellDataFeatures<NavigationNode, String> p) -> new ReadOnlyStringWrapper(p.getValue().getValue().getName()));
        
        
        treeTableView = new TreeTableView<NavigationNode>(treeItemRoot);
        treeTableView.getColumns().addAll(treeTableColumn);
        treeTableView.setShowRoot(false);
        treeTableView.setPrefWidth(300);
        
        treeTableView.setOnMouseClicked(mouseEvent -> {
            if (mouseEvent.getClickCount() == 2) {
                System.out.println("====" + mouseEvent.getSource() + "======"+ mouseEvent.getTarget());
                
                TreeItem<NavigationNode> selectedItem = treeTableView.getSelectionModel().getSelectedItem();
                System.out.println("Selected Text : " + selectedItem.getValue() + " all:" + selectedItem);
                
                if (selectedItem.getValue().getLevel() == 1 || selectedItem.getValue().getLevel() == 2) {
                    if (selectedItem.getChildren().size() > 0) {
                        return;
                    }
                }
                
                if (StringUtils.equalsIgnoreCase("connection", selectedItem.getValue().getType())) {
                    List<Database> databaseList = new BaseDao().getDatabaseList();
                    for (Database database : databaseList) {
                    	NavigationNode navigationNode = new NavigationNode(database.getName(), "db", 2);
                        TreeItem<NavigationNode> treeItem = new TreeItem<>(navigationNode);
                        selectedItem.getChildren().add(treeItem);
                    }
                } else if (StringUtils.equalsIgnoreCase("db", selectedItem.getValue().getType())) {
	                  List<Table> tableList = new BaseDao().getTableList(selectedItem.getValue().getName());
	                  for (Table table : tableList) {
	                	  NavigationNode navigationNode = new NavigationNode(table.getName(), "table", 3);
	                      TreeItem<NavigationNode> tableTreeItem = new TreeItem<>(navigationNode);
	                      selectedItem.getChildren().add(tableTreeItem);
	                      
//	                      ContextMenu contextMenu = new ContextMenu(); 
//	                      MenuItem sqlQueryMenuItem = new MenuItem("SQL查询"); 
//	                      contextMenu.getItems().add(sqlQueryMenuItem);
//	                      contextMenu.show(selectedItem, Side.BOTTOM, 0, 0);
	                      
	                      
	                  }
                } else {
                  try {
                      TreeItem<NavigationNode> parentItem = selectedItem.getParent();
                      NavigationNode parentNavigationNode = parentItem.getValue();
                      String databaseName = parentNavigationNode.getName();
                      
                      TableContext tableContext = new TableContext(databaseName, selectedItem.getValue().getName());
                      this.openTable(masterBorderPane, tableContext);
                      
                      SqlQueryBox SqlQueryBox = new SqlQueryBox(tabPane, tableContext);
                      
                  } catch (SQLException e) {
                      e.printStackTrace();
                    }
                }

            }
        });
    }
    
    private void openTable(BorderPane masterBorderPane, TableContext tableContext) throws SQLException {
        
        ObservableList<Map<String,Object>> tableData = this.buildTableData(tableContext.getTableName(), null, 1, 10);
        List<Column> columnList = tableContext.getColumnList();
        
        TableView table = new TableView();
        for (Column column : columnList) {
            TableColumn tableColumn = new TableColumn(column.getName());
            tableColumn.setSortable(false);
            tableColumn.setCellValueFactory(new MapValueFactory(column.getName()));
            table.getColumns().add(tableColumn);
        }
        table.setItems(tableData);
        
        table.setEditable(true);
        table.autosize();
        table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
        
        this.buildTableDataViewTabPane(tableContext, table);
        masterBorderPane.setCenter(tabPane);
    }
    
    private ObservableList<Map<String,Object>> buildTableData(String tableName, String whereConditon, long startNo, long pageSize) {
        List<Map<String,Object>> dataList =new TableServiceImpl().getTableData(tableName, whereConditon, startNo, pageSize);
        List<Map<String,Object>> targetDataList = Lists.newArrayList();
        for (Map<String,Object> dataMap : dataList) {
            Map<String,Object> targetDataMap = Maps.newHashMap();
            for (Map.Entry<String, Object> entry : dataMap.entrySet()) {
                Object targetValue = entry.getValue();
                if (entry.getValue() instanceof Date) {
                    DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    targetValue = sdf.format((Date)entry.getValue());
                } else if (entry.getValue() instanceof LocalDateTime) {
                    DateTimeFormatter sdf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                    targetValue = sdf.format((LocalDateTime)entry.getValue());
                } else if (entry.getValue() instanceof LocalDate) {
                    DateTimeFormatter sdf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
                    targetValue = sdf.format((LocalDate)entry.getValue());
                }
                
                targetDataMap.put(entry.getKey(), targetValue);
            }
            targetDataList.add(targetDataMap);
        }
        
        ObservableList<Map<String,Object>> tableData = FXCollections.observableArrayList(targetDataList);
        return tableData;
    }
    
    private void buildTableDataViewTabPane(TableContext tableContext, TableView table) {
        Tab tab1 = new Tab(tableContext.getTableName() + "@" + tableContext.getDatabaseName());
        //tab1.setContent(table);

        ConditionFilterBox conditionFilterBox = new ConditionFilterBox(tableContext, table);
        
        VBox vBox = new VBox();
        vBox.getChildren().add(conditionFilterBox.gethBox());
        vBox.getChildren().add(table);
        
        PageBox pageBox = new PageBox(tableContext, table);

        vBox.getChildren().add(pageBox.getBox());
        tab1.setContent(vBox);
        
        // 不同连接的选项卡用不同背景颜色区分
        tab1.setStyle("-fx-background-color: -fx-outer-border, -fx-text-box-border, #87CEFA;");
        tabPane.getTabs().add(tab1);
        tabPane.getSelectionModel().select(tab1);
        
        TabPaneContextMenu tabPaneContextMenu = new TabPaneContextMenu(tabPane);
        tabPane.setContextMenu(tabPaneContextMenu.getContextMenu());
        
    }
    
    private void initTabPane() {
        if (Objects.isNull(tabPane)) {
            tabPane = new TabPane();
            tabPane.setOnMouseClicked(mouseEvent -> {
                // 双击选项卡则关闭当前选项卡
                if (mouseEvent.getClickCount() == 2) {
                    Tab selectedTab = tabPane.getSelectionModel().getSelectedItem();
                    tabPane.getTabs().remove(selectedTab);
                }
            });
        }
    }

    public TreeTableView<NavigationNode> getTreeTableView() {
        return treeTableView;
    }

    public void setTreeTableView(TreeTableView<NavigationNode> treeTableView) {
        this.treeTableView = treeTableView;
    }
}
